//
//  WaveEffect.cpp
//  client
//
//  Created by will on 18/07/2017.
//
//

#include "WaveEffect.hpp"


WaveEffect* WaveEffect::create(const std::string& imageFile,const std::vector<float>& waves)
{
    auto ret = new (std::nothrow) WaveEffect();
    if(ret->initWithFile(imageFile))
    {
        ret->setWaves(waves);
        return ret;
    }
    return nullptr;
}

WaveEffect::WaveEffect()
:_vertices(nullptr)
{
    
}

WaveEffect::~WaveEffect()
{
    
}

bool WaveEffect::initWithFile(const std::string& filename)
{
    if(LineEffect::initWithFile(filename))
    {
        return true;
    }
    return false;
}

void WaveEffect::setWaves(const std::vector<float>& waves)
{
    _waves = waves;
    buildVertices(waves);
}

void WaveEffect::updateLinkPos()
{
    LineEffect::updateLinkPos();
    buildVertices(_waves);
}

void WaveEffect::buildVertices(const std::vector<float>& waves)
{
    int count = (int)waves.size();
    _nuPoints = count;
    
    if(!_vertices)
    {
        _vertices = (Vec2*)malloc(sizeof(Vec2) * count*2);
        _texCoords = (Tex2F*)malloc(sizeof(Tex2F) * count*2);
        _colorPointer =  (GLubyte*)malloc(sizeof(GLubyte) * count * 2 * 4);
    }

    Vec2* pointVertexes = (Vec2*)malloc(sizeof(Vec2) * count);
    
    float dis = _start.distance(_end)/count;

    Vec4 pos;
    for(int i=0;i<count;++i)
    {
        pointVertexes[i].x = dis*(i);
        pointVertexes[i].y = waves[i-1];
    }
    
    float stroke = getContentSize().height;
    
    ccVertexLineToPolygon(pointVertexes, stroke, _vertices, 0, count);
    
    CC_SAFE_FREE(pointVertexes);
    
    for( int i=0; i < count; i++ ) {
        if(i%2==0)
        {
            _texCoords[i*2] = Tex2F(0, 0);
            _texCoords[i*2+1] = Tex2F(1, 1);
        }
        else
        {
            _texCoords[i*2] = Tex2F(1, 0);
            _texCoords[i*2+1] = Tex2F(0, 1);
        }

        const unsigned int offset = i*8;
        *((Color3B*)(_colorPointer + offset)) = getColor();
        *((Color3B*)(_colorPointer + offset+4)) = getColor();
        _colorPointer[offset+3] = 255;
        _colorPointer[offset+7] = 255;
    }
    
    _dirty =true;
}
/*
void WaveEffect::updateVertices()
{
    float dis = _start.distance(_end)/_nuPoints;
    
    for(int i=0;i<_nuPoints;++i)
    {
        int vi = i*8;
        _vertices[vi].x = _start.x+dis*(i-1);
        _vertices[vi+1].y = _waves[i-1];
        

        const unsigned int offset = _nuPoints*8;
        *((Color3B*)(_colorPointer + offset)) = _realColor;
        *((Color3B*)(_colorPointer + offset+4)) = _realColor;
        _colorPointer[offset+3] = 255;
        _colorPointer[offset+7] = 255;
    }
}
*/

void WaveEffect::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
    if(_nuPoints <= 1)
        return;
    _customCommand.init(_globalZOrder, transform, flags);
    _customCommand.func = CC_CALLBACK_0(WaveEffect::onDraw, this, transform, flags);
    renderer->addCommand(&_customCommand);
    
    if(_dirty)
    {
        Vec4 pos;
        for(int i=0;i<_nuPoints*2;++i)
        {
            pos.x = _vertices[i].x; pos.y = _vertices[i].y; pos.z = _positionZ;pos.w = 1;
            _modelViewTransform.transformVector(&pos);
            _vertices[i].x = pos.x;
            _vertices[i].y = pos.y;
        }
        _dirty = false;
    }

}

void WaveEffect::onDraw(const Mat4 &transform, uint32_t flags)
{
    getGLProgram()->use();
    getGLProgram()->setUniformsForBuiltins(transform);
    
    GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX );
    GL::blendFunc( _blendFunc.src, _blendFunc.dst );
    
    GL::bindTexture2D( _texture );
    
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, 0, _texCoords);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, _colorPointer);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)_nuPoints*2);
    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, _nuPoints*2);
}
